/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#include "CachePool.h"

#include <algorithm>
#include <atomic>
#include <future>
#include <sstream>
#include <thread>

#include "Utility/Logging/SGLogger.h"

using namespace SG::DBManager;

// 更新指定key的缓存项内存大小
bool CachePool::UpdateMemorySize (const std::string& key, std::size_t newSize)
{
    std::lock_guard<std::mutex> lock (m_mutex);
    auto                        it = m_cache.find (key);
    if (it == m_cache.end ())
    {
        return false;
    }
    auto& metadata = it->second->metadata;
    // 更新全局内存计数
    if (newSize > metadata.memorySize)
    {
        m_currentMemorySize += (newSize - metadata.memorySize);
    }
    else
    {
        m_currentMemorySize -= (metadata.memorySize - newSize);
    }
    metadata.memorySize = newSize;
    return true;
}

CachePool::CachePool (std::size_t maxMemorySize, std::chrono::milliseconds cleanupIntervalMs)
    : m_maxMemorySize (maxMemorySize), m_currentMemorySize (0), m_cleanupInterval (cleanupIntervalMs), m_stopCleanup (false)
{
    SGTrace << "CachePool initialized with maxMemorySize=" << maxMemorySize << " bytes" << '\n';
}

CachePool::~CachePool ()
{
    SGTrace << "CachePool: Destructor called" << '\n';

    try
    {
        StopCleanupThread ();
    }
    catch (const std::exception& e)
    {
        SGError << "CachePool: Error in destructor while stopping cleanup thread: " << e.what () << '\n';
    }

    Clear ();
    SGTrace << "CachePool: Destructor completed" << '\n';
}

bool CachePool::Contains (const std::string& key)
{
    std::lock_guard<std::mutex> const lock (m_mutex);

    auto it = m_cache.find (key);
    if (it == m_cache.end ())
    {
        return false;
    }

    // 检查是否过期
    return !IsExpired (it->second->metadata);
}

bool CachePool::Remove (const std::string& key)
{
    std::lock_guard<std::mutex> const lock (m_mutex);

    auto it = m_cache.find (key);
    if (it == m_cache.end ())
    {
        return false;
    }

    FreeItem (it->second->metadata);
    m_lruList.erase (it->second);
    m_cache.erase (it);

    SGTrace << "CachePool: Removed item '" << key << "'" << '\n';
    return true;
}

void CachePool::Clear ()
{
    std::lock_guard<std::mutex> const lock (m_mutex);

    // 释放所有缓存项
    for (auto& node : m_lruList)
    {
        FreeItem (node.metadata);
    }

    m_cache.clear ();
    m_lruList.clear ();
    m_currentMemorySize = 0;

    SGTrace << "CachePool: Cleared all items" << '\n';
}

std::size_t CachePool::CleanupExpired ()
{
    std::lock_guard<std::mutex> const lock (m_mutex);
    return CleanupExpiredInternal ();
}

std::size_t CachePool::CleanupExpiredInternal ()
{
    // 假设调用者已经持有锁

    std::size_t removedCount = 0;
    auto        it           = m_lruList.begin ();

    while (it != m_lruList.end ())
    {
        if (IsExpired (it->metadata))
        {
            SGTrace << "CachePool: Cleaning up expired item '" << it->key << "'" << '\n';

            FreeItem (it->metadata);
            m_cache.erase (it->key);
            it = m_lruList.erase (it);
            ++removedCount;
        }
        else
        {
            ++it;
        }
    }

    return removedCount;
}

std::size_t CachePool::Size () const
{
    std::lock_guard<std::mutex> const lock (m_mutex);
    return m_cache.size ();
}

std::size_t CachePool::MemoryUsage () const
{
    std::lock_guard<std::mutex> const lock (m_mutex);
    return m_currentMemorySize;
}

std::string CachePool::GetStatistics () const
{
    std::lock_guard<std::mutex> const lock (m_mutex);

    std::ostringstream oss;
    oss << "CachePool Statistics:\n";
    oss << "  Items: " << m_cache.size () << "\n";
    oss << "  Memory: " << m_currentMemorySize << "/" << m_maxMemorySize << " bytes\n";

    return oss.str ();
}

void CachePool::StartCleanupThread ()
{
    // 如果线程已经存在且可join，先停止它
    if (m_cleanupThread && m_cleanupThread->joinable ())
    {
        return;  // 线程已经在运行
    }

    try
    {
        m_stopCleanup   = false;
        m_cleanupThread = std::make_unique<std::thread> (&CachePool::CleanupThreadFunc, this);
        SGTrace << "CachePool: Started cleanup thread" << '\n';
    }
    catch (const std::exception& e)
    {
        SGError << "CachePool: Failed to start cleanup thread: " << e.what () << '\n';
        m_cleanupThread.reset ();
    }
}

void CachePool::StopCleanupThread ()
{
    // 首先设置停止标志
    m_stopCleanup = true;

    // 立即唤醒清理线程
    {
        std::lock_guard<std::mutex> const lock (m_cleanupMutex);
        m_cleanupCv.notify_one ();
    }

    if (m_cleanupThread)
    {
        if (m_cleanupThread->joinable ())
        {
            try
            {
                // 由于使用了条件变量，线程应该能够快速响应停止信号
                // 但仍然使用超时机制作为安全保障
                auto future = std::async (std::launch::async, [this] () { m_cleanupThread->join (); });

                // 设置较短的超时时间，因为线程应该很快响应
                auto timeout = std::chrono::milliseconds (100);  // 100ms应该足够了

                if (future.wait_for (timeout) == std::future_status::timeout)
                {
                    SGError << "CachePool: Cleanup thread did not stop within 100ms, detaching..." << '\n';
                    m_cleanupThread->detach ();
                }
                else
                {
                    SGTrace << "CachePool: Stopped cleanup thread" << '\n';
                }
            }
            catch (const std::exception& e)
            {
                SGError << "CachePool: Error stopping cleanup thread: " << e.what () << '\n';
            }
        }
        m_cleanupThread.reset ();
    }
}

void CachePool::RemoveTail ()
{
    if (m_lruList.empty ())
    {
        return;
    }

    auto tailIt = std::prev (m_lruList.end ());
    SGTrace << "CachePool: Removing item '" << tailIt->key << "' to free memory" << '\n';

    FreeItem (tailIt->metadata);
    m_cache.erase (tailIt->key);
    m_lruList.erase (tailIt);
}

bool CachePool::IsExpired (const CacheItemMetadata& metadata) const
{
    if (metadata.ttl.count () == 0)
    {
        return false;  // 永不过期
    }

    auto now     = std::chrono::steady_clock::now ();
    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds> (now - metadata.createTime);

    return elapsed >= metadata.ttl;
}

void CachePool::FreeItem (const CacheItemMetadata& metadata)
{
    if (metadata.dataPtr && metadata.destructor)
    {
        metadata.destructor (metadata.dataPtr);
    }

    m_currentMemorySize -= metadata.memorySize;
}

void CachePool::EnforceCapacityLimits ()
{
    std::lock_guard<std::mutex> const lock (m_mutex);
    EnforceCapacityLimitsInternal ();
}

void CachePool::EnforceCapacityLimitsInternal ()
{
    // 假设调用者已经持有锁

    // 移除过期项
    CleanupExpiredInternal ();

    // 检查内存限制
    while (m_currentMemorySize > m_maxMemorySize && !m_lruList.empty ())
    {
        SGTrace << "CachePool: Removing LRU item due to memory limit" << '\n';
        RemoveTail ();
    }
}

void CachePool::CleanupThreadFunc ()
{
    std::unique_lock<std::mutex> lock (m_cleanupMutex);

    while (!m_stopCleanup)
    {
        try
        {
            // 使用条件变量等待，可以被立即唤醒
            if (m_cleanupCv.wait_for (lock, m_cleanupInterval, [this] { return m_stopCleanup.load (); }))
            {
                // 如果是因为停止信号被唤醒，退出循环
                break;
            }
            SGTrace << "Start CleanupThreadFunc";
            // 如果是因为超时被唤醒，执行清理任务
            if (!m_stopCleanup)
            {
                // 释放条件变量的锁，避免在清理过程中阻塞StopCleanupThread
                lock.unlock ();

                std::size_t const removed = CleanupExpired ();
                if (removed > 0)
                {
                    SGTrace << "CachePool: Cleanup thread removed " << removed << " expired items" << '\n';
                }

                // 重新获取锁用于下次循环
                lock.lock ();
            }
        }
        catch (const std::exception& e)
        {
            SGError << "CachePool cleanup thread error: " << e.what () << '\n';
        }
    }
}
